home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks '96 / Internet Chooser / reggie / light / socket.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-21  |  16.2 KB  |  584 lines  |  [TEXT/MMCC]

  1. /* File "socket.cpp", Light Sockets - Copyright (C) Matt Slot, 1996           */
  2. /* Foundation layer for the Light Sockets networking abstraction routines.    */
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <time.h>
  8.  
  9. #include "stddebug.h"
  10. #include "stdtypes.h"
  11.  
  12. #include "datagram.h"
  13. #include "netstack.h"
  14. #include "platform.h"
  15. #include "socket.h"
  16.  
  17. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  18. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  19.  
  20. Socket::Socket() {
  21.     SocketResult &error = instError;
  22.  
  23.     error = eSocketNoError;
  24.     
  25.     inited = false;
  26.     bound = false;
  27.     stack = 0;
  28.     
  29. #ifdef _DEBUG
  30.     logEnabled = false;
  31.     logBuffers[0] = 0;
  32.     logBuffers[1] = 0;
  33. #endif
  34.     }
  35.  
  36. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  37. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  38.  
  39. Socket::~Socket() {
  40.     Socket::Dispose();
  41.     }
  42.  
  43. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  44. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  45. #pragma mark -
  46.  
  47. SocketResult Socket::Create(SocketType socketType) {
  48.     SocketResult &error = instError;
  49.  
  50.     /* Parameter validation */
  51.     qThrowIfError(error, 0);
  52.  
  53.     /* Structure initialization */
  54.     this->socketType = socketType;
  55.     spinProc = SpinStub;
  56.     spinRefcon = 0;
  57.     
  58.     /* Locate, instantiate, and initialize the network stack */    
  59.     qThrowIfError(SelectNetworkStack(this, stack), 0);
  60.     qThrowIfNull(stack, eSocketErrInternal, kSocketErrInternalStr);
  61.     qThrowIfError(stack->DoLoad(), 0);
  62.     qThrowIfError(stack->DoCreate(), 0);
  63.     
  64. #ifdef _DEBUG
  65.     qThrowIfNull(logBuffers[0] = new char[kSocketLoggingSize], eSocketErrOutOfMem,
  66.             kSocketErrBadParamStr);
  67.     qThrowIfNull(logBuffers[1] = new char[kSocketLoggingSize], eSocketErrOutOfMem,
  68.             kSocketErrBadParamStr);
  69. #endif
  70.  
  71. /* CATCH */
  72.     qCatch();
  73.     
  74.     if (error) 
  75.         Dispose();
  76.  
  77.     return(error);
  78.     }
  79.  
  80. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  81. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  82.  
  83. SocketResult Socket::Tickle() {
  84.     SocketResult &error = instError;
  85.     
  86.     /* Parameter validation */
  87.     qThrowIfError(error, 0);
  88.     qAssertIfNull(stack, eSocketErrInternal, kSocketErrInternalStr);
  89.  
  90.     qThrowIfError(stack->DoTickle(), 0);
  91.     qThrowIfError(CallSpinProc(), 0);
  92.     
  93. /* CATCH */
  94.     qCatch();
  95.  
  96.     return(error);
  97.     }
  98.     
  99. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  100. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  101.  
  102. SocketResult Socket::Dispose() {
  103.     SocketResult &error = instError;
  104.     
  105.     if (stack) {
  106.         qTraceIfError(stack->DoDispose(), 0);
  107.         qTraceIfError(stack->DoUnload(), 0);
  108.         delete stack;
  109.         stack = 0;
  110.         }
  111.  
  112. #ifdef _DEBUG
  113.     if (IsLogging()) DisableLogging();
  114.     if (curLogBuffer && *curLogBuffer) CallSpinProc();
  115.     if (logBuffers[0]) delete logBuffers[0];
  116.     if (logBuffers[1]) delete logBuffers[1];
  117. #endif
  118.  
  119. /* CATCH */
  120.     qCatch();
  121.  
  122.     return(error);
  123.     }
  124.     
  125. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  126. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  127. #pragma mark -
  128.  
  129. SocketResult Socket::Bind(SocketAddressPtr reqAddress,
  130.         SocketAddressPtr retAddress) {
  131.     SocketResult &error = instError;
  132.     
  133.     /* Parameter validation */
  134.     qThrowIfError(error, 0);
  135.     qAssertIfNull(stack, eSocketErrInternal, kSocketErrInternalStr);
  136.     
  137.     qThrowIfError(stack->DoBind(reqAddress, retAddress), 0);
  138.     
  139. /* CATCH */
  140.     qCatch();
  141.  
  142.     return(error);
  143.     }
  144.     
  145. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  146. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  147.  
  148. SocketResult Socket::Unbind() {
  149.     SocketResult &error = instError;
  150.     
  151.     /* Parameter validation */
  152.     qThrowIfError(error, 0);
  153.     qAssertIfNull(stack, eSocketErrInternal, 0);
  154.         
  155.     qThrowIfError(stack->DoUnbind(), 0);
  156.     
  157. /* CATCH */
  158.     qCatch();
  159.  
  160.     return(error);
  161.     }
  162.     
  163.  
  164. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  165. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  166. #pragma mark -
  167.  
  168. SocketResult Socket::GetInstError() {
  169.     return(this->instError);
  170.     }
  171.  
  172. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  173. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  174.  
  175. void Socket::ResetInstError() {
  176.     this->instError = eSocketNoError;
  177.     }
  178.  
  179. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  180. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  181.  
  182. SocketType Socket::GetSocketType() {
  183.     return(this->socketType);
  184.     }
  185.  
  186. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  187. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  188.  
  189. Bool8 Socket::IsSocketInited() {
  190.     return(this->inited);
  191.     }
  192.  
  193. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  194. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  195.  
  196. void Socket::SetSocketInited(Bool8 inited) {
  197.     this->inited = inited;
  198.     }
  199.  
  200. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  201. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  202.  
  203. Bool8 Socket::IsSocketBound(SocketAddressPtr boundTo) {
  204.     if (this->bound && boundTo)
  205.         *boundTo = this->boundTo;
  206.     return(this->bound);
  207.     }
  208.  
  209. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  210. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  211.  
  212. void Socket::SetSocketBound(Bool8 bound, SocketAddress &boundTo) {
  213.     if (this->bound = bound)
  214.         this->boundTo = boundTo;
  215.     }
  216.  
  217. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  218. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  219. #pragma mark -
  220.  
  221. SocketResult Socket::GetSpinProc(SocketSpinProc &proc, void * &refcon) {
  222.     SocketResult &error = instError;
  223.     
  224.     /* Parameter validation */
  225.     qThrowIfError(error, 0);
  226.  
  227.     proc = spinProc;
  228.     refcon = spinRefcon;
  229.     
  230. /* CATCH */
  231.     qCatch();
  232.  
  233.     return(error);
  234.     }
  235.  
  236. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  237. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  238.  
  239. SocketResult Socket::SetSpinProc(SocketSpinProc proc, void *refcon) {
  240.     SocketResult &error = instError;
  241.     
  242.     /* Parameter validation */
  243.     qThrowIfError(error, 0);
  244.  
  245.     spinProc = (proc) ? proc : SpinStub;
  246.     spinRefcon = (proc) ? refcon : 0;
  247.  
  248. /* CATCH */
  249.     qCatch();
  250.  
  251.     return(error);
  252.     }
  253.  
  254. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  255. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  256.  
  257. SocketResult Socket::CallSpinProc() {
  258.     SocketResult error = eSocketNoError;
  259.     
  260.     /* Parameter validation */
  261.     qThrowIfError(error, 0);
  262.     qAssertIfNull(spinProc, eSocketErrInternal, kSocketErrInternalStr);
  263.  
  264.     /* Make the function call */
  265.     qThrowIfError((*spinProc)(this, spinRefcon), 0);
  266.  
  267. /* CATCH */
  268.     qCatch();
  269.  
  270.     return(error);
  271.     }
  272.  
  273. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  274. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  275.  
  276. SocketResult Socket::SpinStub(SocketRef socket, void *refcon) {
  277.     SocketResult error = eSocketNoError;
  278.     
  279.     /* Parameter validation */
  280.     qThrowIfError(error, 0);
  281.     qAssertIfNull(socket, eSocketErrInternal, kSocketErrInternalStr);
  282.  
  283. #if defined(PLATFORM_MAC)
  284.     SystemTask();
  285. #endif
  286.  
  287. /* CATCH */
  288.     qCatch();
  289.  
  290.     return(error);
  291.     }
  292.  
  293. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  294. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  295. #pragma mark -
  296.  
  297. #ifdef _DEBUG
  298.  
  299. SocketResult Socket::EnableLogging(char *filename, Bool8 replacing) {
  300.     SocketResult &error = instError;
  301.  
  302.     /* Parameter validation */
  303.     qThrowIfError(error, 0);
  304.     qThrowIfNull(filename, eSocketErrBadParam, kSocketErrBadParamStr);
  305.     qThrowIfFalse(strlen(filename) < sizeof(logName), 
  306.             eSocketErrBadParam, kSocketErrBadParamStr);
  307.  
  308.     strcpy(logName, filename);
  309.     curLogBuffer = logBuffers[0];
  310.     *(logBuffers[0]) = 0;
  311.     *(logBuffers[1]) = 0;
  312.     
  313.     qThrowIfError(GetSpinProc(logSpinProc, logSpinRefcon), 0);
  314.     qThrowIfError(SetSpinProc(LoggingSpinStub, 0), 0);
  315.     switch(qGetSocketTransfer(GetSocketType())) {
  316.         case eSocketTransferDatagram: 
  317.             qThrowIfError(((DatagramSocketRef) this)->GetWriteProc(
  318.                     (DatagramWriteProc *) &logWriteProc, &logWriteRefcon), 0);
  319.             qThrowIfError(((DatagramSocketRef) this)->SetWriteProc(
  320.                     (DatagramWriteProc) LoggingDatagramWriteStub, 0), 0);
  321.             qThrowIfError(((DatagramSocketRef) this)->GetReadProc(
  322.                     (DatagramReadProc *) &logReadProc, &logReadRefcon), 0);
  323.             qThrowIfError(((DatagramSocketRef) this)->SetReadProc(
  324.                     (DatagramReadProc) LoggingDatagramReadStub, 0), 0);
  325.             break;
  326.             
  327.         case eSocketTransferStream: 
  328.             qThrowErr(eSocketErrNoSupport, kSocketErrNoSupportStr);
  329.             break;
  330.             
  331.         case eSocketTransferXaction: 
  332.             qThrowErr(eSocketErrNoSupport, kSocketErrNoSupportStr);
  333.             break;
  334.             
  335.         default:
  336.             qThrowErr(eSocketErrInternal, kSocketErrInternalStr);
  337.             break;
  338.         }
  339.  
  340.     logEnabled = true;
  341.     logInited = false;
  342.     logReplace = replacing;
  343.  
  344. /* CATCH */
  345.     qCatch();
  346.  
  347.     return(error);
  348.     }
  349.  
  350. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  351. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  352.  
  353. SocketResult Socket::DisableLogging() {
  354.     SocketResult &error = instError;
  355.     
  356.     logEnabled = false;
  357.     logInited = true;
  358.     logReplace = false;
  359.  
  360. /* CATCH */
  361.     qCatch();
  362.  
  363.     return(error);
  364.     }
  365.  
  366. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  367. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  368.  
  369. Bool8 Socket::IsLogging() {
  370.     return(logEnabled);
  371.     }
  372.  
  373. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  374. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  375.  
  376. SocketResult Socket::LoggingSpinStub(SocketRef socket, void *refcon) {
  377.     SocketResult error = eSocketNoError;
  378.     SInt32 result;
  379.     Char8 *logCopy = 0;
  380.     FILE *logFile = 0;
  381.  
  382.     /* Parameter validation */
  383.     qThrowIfError(error, 0);
  384.     qAssertIfNull(socket, eSocketErrInternal, kSocketErrInternalStr);
  385.     qThrowIfNull(socket->logSpinProc, eSocketErrInternal,
  386.             kSocketErrInternalStr);
  387.     qThrowIfFalse(strlen(socket->logName), eSocketErrBadParam, 
  388.             kSocketErrBadParamStr);
  389.  
  390.     if (*socket->curLogBuffer) {
  391.         
  392.         /* We maintain two buffers because interrupt-based networking continues 
  393.            to accumulate packets and fill the log through the fprintf(), which 
  394.            can be a "Bad Thing(tm)". Swapping the active buffer helps this. */
  395.           
  396.         if (socket->curLogBuffer == socket->logBuffers[0]) {
  397.             socket->curLogBuffer = socket->logBuffers[1];
  398.             logCopy = socket->logBuffers[0];
  399.             }
  400.           else {
  401.             socket->curLogBuffer = socket->logBuffers[0];
  402.             logCopy = socket->logBuffers[1];
  403.             }
  404.     
  405.         logCopy[kSocketLoggingSize-1] = 0;
  406.         
  407.         if (socket->logReplace) {
  408.             qThrowIfNull(logFile = fopen(socket->logName, "w"), 
  409.                     eSocketErrOutOfMem, "Error opening logfile");
  410.             socket->logReplace = false;
  411.             }
  412.           else {
  413.             qThrowIfNull(logFile = fopen(socket->logName, "a"), 
  414.                     eSocketErrOutOfMem, "Error opening logfile");
  415.  
  416.             if (!socket->logInited) {
  417.                 result = fprintf(logFile, "\n");
  418.                 qThrowIfTrue(result < 0, result, "Error writing logfile");
  419.                 }
  420.             }
  421.         
  422.         if (!socket->logInited) {
  423.             socket->logInited = true;
  424.             result = fprintf(logFile, 
  425.                     "Binary dated: " __DATE__ ", " __TIME__ "\n"); 
  426.             qThrowIfTrue(result < 0, result, "Error writing logfile");
  427.                     
  428.             result = fprintf(logFile, "\n");
  429.             qThrowIfTrue(result < 0, result, "Error writing logfile");
  430.             }
  431.         
  432.         result = fprintf(logFile, "%s", logCopy);
  433.         qThrowIfTrue(result < 0, result, "Error writing logfile");
  434.         }
  435.     
  436.     qThrowIfError((*socket->logSpinProc)(socket, socket->logSpinRefcon), 0);
  437.  
  438. /* CATCH */
  439.     qCatch();
  440.  
  441.     if (logCopy) *logCopy = 0;
  442.     if (logFile) qTraceIfError(fclose(logFile), "Error closing logfile");    
  443.  
  444.     return(error);
  445.     }
  446.  
  447. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  448. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  449.  
  450. SocketResult Socket::LoggingDatagramReadStub(Socket *socket, void *refcon,
  451.         Byte8 *dataPtr, UInt32 dataLen, SocketAddressPtr address) {
  452.     SocketResult error = eSocketNoError;
  453.     char *logCopy = 0;
  454.     
  455.     /* Parameter validation */
  456.     qThrowIfError(error, 0);
  457.     qAssertIfNull(socket, eSocketErrInternal, kSocketErrInternalStr);
  458.     qThrowIfNull(socket->curLogBuffer, eSocketErrInternal, kSocketErrInternalStr);
  459.     qThrowIfNull(socket->logReadProc, eSocketErrInternal, kSocketErrInternalStr);
  460.  
  461.     if (socket->logEnabled) {
  462.         UInt32 dataDone;
  463.         Char8 hex[ARBITRARY_BUFFER_SIZE];
  464.         Char8 ascii[ARBITRARY_BUFFER_SIZE];
  465.         
  466.         /* Draw the packet information */
  467.         socket->LoggingConvertBytes((Byte8 *)socket, sizeof(socket), hex, 0, 0);
  468.         strcat(socket->curLogBuffer, hex);
  469.         strcat(socket->curLogBuffer, "- DGM RECV - ");
  470.         for(dataDone = 0; dataDone < address->length; dataDone += 16) {
  471.             socket->LoggingConvertBytes(address->buffer.bytes + dataDone,
  472.                     address->length - dataDone, 0, hex, 0);
  473.             strcat(socket->curLogBuffer, hex);
  474.             }
  475.         strcat(socket->curLogBuffer, "\n");
  476.         
  477.         /* Draw the packet data */
  478.         for(dataDone = 0; dataDone < dataLen; dataDone += 16) {
  479.             socket->LoggingConvertBytes(dataPtr + dataDone, 
  480.                     dataLen - dataDone, 0, hex, ascii);
  481.             strcat(socket->curLogBuffer, "\t\t | ");
  482.             strcat(socket->curLogBuffer, hex);
  483.             strcat(socket->curLogBuffer, "| ");
  484.             strcat(socket->curLogBuffer, ascii);
  485.             strcat(socket->curLogBuffer, "\n");
  486.             }
  487.         }
  488.  
  489.     qThrowIfError((*socket->logReadProc)((DatagramSocketRef) socket,
  490.             socket->logReadRefcon, dataPtr, dataLen, address), 0);
  491.  
  492. /* CATCH */
  493.     qCatch();
  494.  
  495.     return(error);
  496.     }
  497.  
  498. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  499. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  500.  
  501. SocketResult Socket::LoggingDatagramWriteStub(Socket *socket, void *refcon,
  502.         Byte8 *dataPtr, UInt32 dataLen, SocketAddressPtr address) {
  503.     SocketResult error = eSocketNoError;
  504.     char *logCopy = 0;
  505.  
  506.     /* Parameter validation */
  507.     qThrowIfError(error, 0);
  508.     qAssertIfNull(socket, eSocketErrInternal, kSocketErrInternalStr);
  509.     qThrowIfNull(socket->curLogBuffer, eSocketErrInternal, kSocketErrInternalStr);
  510.     qThrowIfNull(socket->logWriteProc, eSocketErrInternal,
  511.             kSocketErrInternalStr);
  512.  
  513.     if (socket->logEnabled) {
  514.         UInt32 dataDone;
  515.         Char8 hex[ARBITRARY_BUFFER_SIZE];
  516.         Char8 ascii[ARBITRARY_BUFFER_SIZE];
  517.         
  518.         /* Draw the packet information */
  519.         socket->LoggingConvertBytes((Byte8 *)socket, sizeof(socket), hex, 0, 0);
  520.         strcat(socket->curLogBuffer, hex);
  521.         strcat(socket->curLogBuffer, "- DGM SEND - ");
  522.         for(dataDone = 0; dataDone < address->length; dataDone += 16) {
  523.             socket->LoggingConvertBytes(address->buffer.bytes + dataDone,
  524.                     address->length - dataDone, 0, hex, 0);
  525.             strcat(socket->curLogBuffer, hex);
  526.             }
  527.         strcat(socket->curLogBuffer, "\n");
  528.         
  529.         /* Draw the packet data */
  530.         for(dataDone = 0; dataDone < dataLen; dataDone += 16) {
  531.             socket->LoggingConvertBytes(dataPtr + dataDone, 
  532.                     dataLen - dataDone, 0, hex, ascii);
  533.             strcat(socket->curLogBuffer, "\t\t | ");
  534.             strcat(socket->curLogBuffer, hex);
  535.             strcat(socket->curLogBuffer, "| ");
  536.             strcat(socket->curLogBuffer, ascii);
  537.             strcat(socket->curLogBuffer, "\n");
  538.             }
  539.         }
  540.  
  541.     qThrowIfError((*socket->logWriteProc)((DatagramSocketRef) socket,
  542.             socket->logReadRefcon, dataPtr, dataLen, address), 0);
  543.  
  544. /* CATCH */
  545.     qCatch();
  546.  
  547.     return(error);
  548.     }
  549.  
  550. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  551. /* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */
  552.  
  553. void Socket::LoggingConvertBytes(Byte8 *dataPtr, UInt32 dataLen, 
  554.         Char8 *addr, Char8 *hex, Char8 *ascii) {
  555.     UInt32 i, j, val;
  556.     Char8 *hexDigits = "0123456789ABCDEF";
  557.     
  558.     if (addr) {
  559.         for(i=(UInt32) dataPtr, j=0; j<8; i<<=4)
  560.             addr[j++] = hexDigits[i>>28];
  561.         addr[j++] = ' ';
  562.         addr[j++] = 0;
  563.         }
  564.     
  565.     if (hex) {
  566.         for(i=j=0; i<16; i++) {
  567.             hex[j++] = (i>=dataLen) ? ':' : hexDigits[(UInt8) dataPtr[i]>>4];
  568.             hex[j++] = (i>=dataLen) ? ':' : hexDigits[(UInt8) dataPtr[i]&0x0F];
  569.             if ((j+1)%9 == 0) hex[j++] = ' ';
  570.             }
  571.         hex[j++] = 0;
  572.         }
  573.     
  574.     if (ascii) {
  575.         for(i=j=0; i<16; i++)
  576.             ascii[j++] = (i>=dataLen) ? ':' : 
  577.                     ((dataPtr[i]<0x20)||(dataPtr[i]>0x7E)) ? '*' : dataPtr[i];
  578.         ascii[j++] = 0;
  579.         }
  580.     }
  581.  
  582. #endif /* _DEBUG */
  583.  
  584.